package com.wei.czz.framework.common.service.impl;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.index.validateCode.ValidateCodeStatusEnum;
import com.wei.czz.common.enums.index.validateCode.ValidateCodeTypeEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.property.MailProperty;
import com.wei.czz.common.po.ValidateCodePo;
import com.wei.czz.common.utils.RandomNumUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.service.MailService;
import com.wei.czz.framework.admin.entity.UserEntity;
import com.wei.czz.framework.common.entity.ValidateCodeEntity;
import com.wei.czz.framework.admin.service.UserService;
import com.wei.czz.framework.common.service.ValidateCodeService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2022-04-28 19:26:33
 * className: MailServiceImpl 邮件服务接口实现类
 * version: 1.0
 * description:
 */
@Service("mailService")
@AllArgsConstructor
public class MailServiceImpl implements MailService {

    private static final Logger log = LoggerFactory.getLogger(MailServiceImpl.class);

    private final MailProperties mailProperties;

    private final MailProperty mailProperty;

    private final UserService userService;

    private final ValidateCodeService validateCodeService;

    private final RedisHashHandler redisHashHandler;

    private final JavaMailSender javaMailSender;

    @Override
    public void sendMail(String email, Integer validateType, HttpServletRequest request) {
        // 查询数据库系统用户表，判断邮箱号是否存在
        List<UserEntity> userList = userService.findUserList(email, null, null);
        if (userList.isEmpty()) {
            if (!(ValidateCodeTypeEnum.REGISTER_USER.getValue().equals(validateType)
                    || ValidateCodeTypeEnum.UPDATE_EMAIL.getValue().equals(validateType))) {
                // 系统不存在邮箱号，且发送的邮件验证码的验证类型不是注册验证码
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(),
                        "网站不存在该邮箱号，请确认，如有问题，请联系管理员处理。");
            }
        } else if (ValidateCodeTypeEnum.REGISTER_USER.getValue().equals(validateType)) {
            // 注册邮件验证码
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(),
                    "网站已经存在该邮箱号注册的账号，请确认，如有问题，请联系管理员处理。");
        }

        Date nowDate = new Date();

        // 查询数据库系统验证码表，获取最后一次发送邮箱验证码的创建事件
        Date lastCreateTime = validateCodeService.getLastCreateTime(email, validateType);
        if (lastCreateTime != null && nowDate.getTime() - lastCreateTime.getTime() <= Constant.MINUTE_NUM) {
            long second = (Constant.MINUTE_NUM - (nowDate.getTime() - lastCreateTime.getTime())) / 1000;
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "发送失败，请" + second + "秒后重试");
        }

        // 获取验证码
        String code = RandomNumUtils.getRandomSixCode();

        // 发送邮件
        this.sendMail(email, validateType, code);

        Long expireTime = nowDate.getTime() + Constant.FIVE_MINUTE_NUM;

        ValidateCodeEntity validateCode = new ValidateCodeEntity();
        validateCode.setAccount(email);
        validateCode.setType(validateType);
        validateCode.setCode(code);
        validateCode.setExpireTime(expireTime);
        validateCode.setAuditTime(CommonEnum.ZERO.getLongValue());
        validateCode.setAuditStatus(ValidateCodeStatusEnum.NONE_AUTH.getValue());
        validateCode.setAuditFailNum(0);
        validateCode.setDeleteStatus(CommonEnum.ZERO.getValue());
        validateCode.setUpdateTime(nowDate);
        validateCode.setUpdateUser(StringUtils.EMPTY);
        validateCode.setUpdateUserId(CommonEnum.ZERO.getLongValue());
        validateCode.setCreateTime(nowDate);
        validateCode.setCreateUser(StringUtils.EMPTY);
        validateCode.setCreateUserId(CommonEnum.ZERO.getLongValue());
        // 操作数据库验证码表，新增一条验证码信息
        validateCodeService.saveOrEdit(validateCode);

        // 记录操作时间、新验证码主键、邮件验证码、验证码过期时间和重置校验失败次数
        ValidateCodePo emailPo = new ValidateCodePo();
        emailPo.setId(validateCode.getId())
                .setCode(code)
                .setExpireTime(expireTime)
                .setAuditFailNum(0);
        // 操作Redis缓存，更新缓存信息
        redisHashHandler.put(RedisConstant.VALIDATE_CODE_MAP, email, emailPo);
    }

    /**
     * 发送邮件
     * @param email        收件人邮箱号
     * @param validateType 验证类型[1-免密登录 2-找回密码 3-用户注册]
     * @param code         验证码
     */
    private void sendMail(String email, Integer validateType, String code) {
        log.info("开始发送邮件。email={} code={}", email, code);
        if (mailProperty.getOpen()) {
            SimpleMailMessage mailMessage = new SimpleMailMessage();
            // 设置邮件发送者
            mailMessage.setFrom(mailProperties.getUsername());
            // 设置邮件接收者
            mailMessage.setTo(email);

            String subject;
            String text;
            if (ValidateCodeTypeEnum.FAST_LOGIN.getValue().equals(validateType)) {
                subject = "登录验证码";
                text = "【博客网站】尊敬的用户，您的登录验证码：" + code + " ，该验证码五分钟内有效，请勿泄漏与他人！";
            } else {
                subject = "注册验证码";
                text = "【博客网站】尊敬的用户，您的注册验证码：" + code + " ，该验证码五分钟内有效，请勿泄漏与他人！";
            }
            // 设置邮件主题
            mailMessage.setSubject(subject);
            // 设置邮件内容
            mailMessage.setText(text);

            try {
                // 发送邮件
                javaMailSender.send(mailMessage);

            } catch (MailException e) {
                e.printStackTrace();
                throw new CzzException("邮件发送失败，请务必及时处理");
            }
        }
    }
}
